package com.evil.application.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evil.application.enums.GenerateSnEnum;
import com.evil.application.enums.ResettingTypeEnum;
import com.evil.application.mapper.GenerateSnMapper;
import com.evil.application.pojo.dto.order.OrderSnSettingDTO;
import com.evil.application.pojo.dto.order.SnSettingBaseDTO;
import com.evil.application.pojo.entity.GenerateSn;
import com.evil.application.service.GenerateSnService;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.family.enums.RCodeEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * 序列号生成表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@Service
@AllArgsConstructor
public class GenerateSnServiceImpl extends ServiceImpl<GenerateSnMapper, GenerateSn> implements GenerateSnService {

    /**
     * 生成编号
     *
     * @param snSettingBaseDTO snSettingDTO
     * @return String
     */
    @Override
    public synchronized String generateSn(SnSettingBaseDTO snSettingBaseDTO) {
        Long enterpriseId = snSettingBaseDTO.getEnterpriseId();
        String type = snSettingBaseDTO.getType();
        Integer length = snSettingBaseDTO.getLength();
        String prefix = snSettingBaseDTO.getPrefix();
        String suffix = snSettingBaseDTO.getSuffix();

        GenerateSnEnum generateSnEnum = GenerateSnEnum.isExistByType(type);
        if (null == generateSnEnum) {
            throw new BusinessException(RCodeEnum.GENERATE_SN_ERROR);
        }
        String t = String.format("%s_%s", type, enterpriseId);
        GenerateSn generateSn = this.baseMapper.findByType(t).orElseGet(() -> {
            GenerateSn g = new GenerateSn();
            g.setType(t);
            g.setSn(1L);
            g.setMinLength(length);
            g.setPrefix(prefix);
            g.setSuffix(suffix);
            g.setResetTime(new Date());

            if (this.baseMapper.insert(g) != 1) {
                log.error("【生成编号】，插入新的编号规则失败");
                throw new BusinessException(RCodeEnum.UPDATE_ERROR);
            }
            return g;
        });

        // 自增更新
        if (this.baseMapper.updateByType(t) < 1) {
            throw new BusinessException(RCodeEnum.GENERATE_SN_ERROR);
        }
        return generateDefault(generateSn, StringUtils.isNotBlank(prefix), StringUtils.isNotBlank(suffix));
    }

    /**
     * 生成编号
     *
     * @param applicationOrderSnSettingDTO applicationOrderSnSettingDTO
     * @return String
     */
    @Override
    public synchronized String generateSn(OrderSnSettingDTO applicationOrderSnSettingDTO) {
        Long enterpriseId = applicationOrderSnSettingDTO.getEnterpriseId();
        Long applicationId = applicationOrderSnSettingDTO.getApplicationId();
        String type = applicationOrderSnSettingDTO.getType();
        Integer length = applicationOrderSnSettingDTO.getLength();
        Integer resettingType = applicationOrderSnSettingDTO.getResettingType();
        String prefix = applicationOrderSnSettingDTO.getPrefix();
        String suffix = applicationOrderSnSettingDTO.getSuffix();

        GenerateSnEnum generateSnEnum = GenerateSnEnum.isExistByType(type);
        if (null == generateSnEnum) {
            throw new BusinessException(RCodeEnum.GENERATE_SN_ERROR);
        }
        String t = String.format("%s-%s-%s", type, enterpriseId, applicationId);
        GenerateSn generateSn = this.baseMapper.findByType(t).orElseGet(() -> {
            GenerateSn g = new GenerateSn();
            g.setType(t);
            g.setSn(1L);
            g.setMinLength(length);
            g.setPrefix(prefix);
            g.setSuffix(suffix);
            g.setResetTime(new Date());

            if (this.baseMapper.insert(g) != 1) {
                log.error("【生成编号】，插入新的编号规则失败");
                throw new BusinessException(RCodeEnum.UPDATE_ERROR);
            }
            return g;
        });

        // 是否需要更新
        boolean needUpdate = false;

        // 重置
        if (ResettingTypeEnum.UN_RESETTING.getId() != resettingType) {
            Date now = new Date();
            DateTime begin = null;
            DateTime end = null;
            if (ResettingTypeEnum.YEAR.getId() == resettingType) {
                // 每年重置
                begin = DateUtil.beginOfYear(now);
                end = DateUtil.endOfYear(now);
            } else if (ResettingTypeEnum.SEASON.getId() == resettingType) {
                // 每季重置
                begin = DateUtil.beginOfQuarter(now);
                end = DateUtil.endOfQuarter(now);
            } else if (ResettingTypeEnum.MONTH.getId() == resettingType) {
                // 每月重置
                begin = DateUtil.beginOfMonth(now);
                end = DateUtil.endOfMonth(now);
            } else if (ResettingTypeEnum.WEEK.getId() == resettingType) {
                // 每周重置
                begin = DateUtil.beginOfWeek(now);
                end = DateUtil.endOfWeek(now);
            } else if (ResettingTypeEnum.DAY.getId() == resettingType) {
                // 每日重置
                begin = DateUtil.beginOfDay(now);
                end = DateUtil.endOfDay(now);
            }

            if (null != begin) {
                if (null == generateSn.getResetTime() || !DateUtil.isIn(generateSn.getResetTime(), begin, end)) {
                    generateSn.setSn(1L);
                    generateSn.setResetTime(now);
                    needUpdate = true;
                }
            }
        }

        // 最小长度
        if (!ObjectUtil.equal(generateSn.getMinLength(), length)) {
            generateSn.setMinLength(length);
            needUpdate = true;
        }

        // 是否需要更新
        if (needUpdate) {
            if (this.baseMapper.updateById(generateSn) != 1) {
                throw new BusinessException(RCodeEnum.GENERATE_SN_ERROR);
            }
        }

        // 自增更新
        if (this.baseMapper.updateByType(t) < 1) {
            throw new BusinessException(RCodeEnum.GENERATE_SN_ERROR);
        }
        return generateDefault(generateSn, StringUtils.isNotBlank(prefix), StringUtils.isNotBlank(suffix));
    }

    /**
     * 默认生成方法
     *
     * @param generateSn generateSn
     * @return String
     */
    private String generateDefault(GenerateSn generateSn, boolean userPrefix, boolean userSuffix) {
        StringBuilder sn = new StringBuilder(generateSn.getSn() + "");
        String retSn = generateSn.getPrefix(userPrefix) + sn + generateSn.getSuffix(userSuffix);
        if (ObjectUtil.isNotNull(generateSn.getMinLength())) {
            while (sn.length() < generateSn.getMinLength()) {
                sn.insert(0, "0");
                retSn = generateSn.getPrefix(userPrefix) + sn + generateSn.getSuffix(userSuffix);
            }
        }
        return retSn;
    }
}
